package FooBarBibliotheque;

import java.io.Serializable;
import java.util.*;


/* @authors vasquezs, haffafa, baldinof */
public class Bibliotheque implements Serializable {

    private static final long serialVersionUID = 1L;
    private HashMap<String, Ouvrage> ouvrages;
    private HashMap<Integer, Lecteur> lecteurs;
    private HashSet<ElementRecherche> elements;
    private HashMap<String, Periodique> periodiques;

    public Bibliotheque() {
        periodiques = new HashMap<String, Periodique>();
        ouvrages = new HashMap<String, Ouvrage>();
        lecteurs = new HashMap<Integer, Lecteur>();
        elements = new HashSet<ElementRecherche>();
    }

    private Lecteur unLecteur(int num) {
        return lecteurs.get(num);
    }

    private Ouvrage unOuvrage(String ISBN) {
        return ouvrages.get(ISBN);
    }

    private Auteur unAuteur(String nom, String prenom) {
        ElementRecherche temp;
        Auteur a = null;
        Iterator<ElementRecherche> iter = elements.iterator();
        while (iter.hasNext() && a == null) {
            temp = iter.next();
            if (temp instanceof Auteur) {
                if (temp.getElement().contentEquals(nom + " " + prenom)) {
                    a = (Auteur) temp;
                }
            }
        }
        return a;
    }

    private MotClefTitre unMotClefTitre(String mot) {
        ElementRecherche temp;
        MotClefTitre m = null;
        Iterator<ElementRecherche> iter = elements.iterator();
        while (iter.hasNext() && m == null) {
            temp = iter.next();
            if (temp instanceof MotClefTitre) {
                if (temp.getElement().contentEquals(mot)) {
                    m = (MotClefTitre) temp;
                }
            }
        }
        return m;
    }

    private MotClefContenu unMotClefContenu(String mot) {
        ElementRecherche temp;
        MotClefContenu m = null;
        Iterator<ElementRecherche> iter = elements.iterator();
        while (iter.hasNext() && m == null) {
            temp = iter.next();
            if (temp instanceof MotClefContenu) {
                if (temp.getElement().contentEquals(mot)) {
                    m = (MotClefContenu) temp;
                }
            }
        }
        return m;
    }

    public void nouveauLecteur() {
        String nom, prenom, adresse, tel;
        int age, num;
        num = EntreSortie.lireEntier("Veuillez entrer le numero du lecteur : ");
        Lecteur l = unLecteur(num);
        if (l == null) {
            nom = EntreSortie.lireChaine("Veuillez entrer le nom du lecteur : ");
            prenom = EntreSortie.lireChaine("Veuillez entrer le prenom du lecteur : ");
            age = EntreSortie.lireEntier("Veuillez entrer le age du lecteur : ");
            adresse = EntreSortie.lireChaine("Veuillez entrer le adresse du lecteur : ");
            tel = EntreSortie.lireChaine("Veuillez entrer le tel du lecteur : ");
            l = new Lecteur(num, nom, prenom, age, adresse, tel);
            lierLecteur(l, num);

        } else {
            EntreSortie.afficherMessage("Lecteur existant");

        }
    }

    public void nouvelExemplaire() {
        Ouvrage o;
        String ISBN;
        ISBN = EntreSortie.lireChaine("Numéro ISBN: ");
        o = unOuvrage(ISBN);
        if (o == null) {
            char continu;
            continu = EntreSortie.lireChaine("Ouvrage inexistant. Voulez vous creer l'ouvrage (o pour accepter) : ").charAt(0);
            if (continu == 'o' || continu == 'O') {
                EntreSortie.afficherMessage("Creation de l'Ouvrage:\n");
                o = nouvelOuvrage();
                GregorianCalendar dateReception = EntreSortie.lireDate("date de reception de l'exemplaire : ");
                String aTE = EntreSortie.lireChaine("Veuillez entrer le type d'exemplaire (consultable,empruntable): ");
                TypeExemplaire typeExemplaire = null;
                if (aTE.equals("consultable")) {
                    typeExemplaire = TypeExemplaire.consultable;
                }
                if (aTE.equals("empruntable")) {
                    typeExemplaire = TypeExemplaire.empruntable;
                }
                o.creerExemplaire(dateReception, typeExemplaire);
            }
        } else {
            GregorianCalendar dateReception = EntreSortie.lireDate("date de reception de l'exemplaire : ");
            String aTE = EntreSortie.lireChaine("Veuillez entrer le type d'exemplaire (consultable,empruntable): ");
            TypeExemplaire typeExemplaire = null;
            if (aTE.equals("consultable")) {
                typeExemplaire = TypeExemplaire.consultable;
            }
            if (aTE.equals("empruntable")) {
                typeExemplaire = TypeExemplaire.empruntable;
            }
            o.creerExemplaire(dateReception, typeExemplaire);


        }


    }

    public Ouvrage nouvelOuvrage() {
        GregorianCalendar dateParution;
        String ISBN, nomEditeur, titre;
        String aPublic;
        Public typePublic = null;
        ISBN = EntreSortie.lireChaine("Veuillez entrer le numero ISBN de l'ouvrage : ");
        Ouvrage o = unOuvrage(ISBN);
        if (o == null) {
            nomEditeur = EntreSortie.lireChaine("Veuillez entrer le nom de l'editeur : ");
            dateParution = EntreSortie.lireDate("Veuillez entrer la date de parution : ");
            titre = EntreSortie.lireChaine("Veuillez entrer le titre : ");
            aPublic = EntreSortie.lireChaine("Veuillez entrer le type public (ado,adulte ou enfant): ");

            if (aPublic.equals("adulte")) {
                typePublic = Public.adulte;
            }
            if (aPublic.equals("ado")) {
                typePublic = Public.ado;
            }
            if (aPublic.equals("enfant")) {
                typePublic = Public.enfant;
            }
            o = new Ouvrage(ISBN, nomEditeur, dateParution, titre, typePublic);
            lierElementRechercheDocumentContenue(o);
            lierOuvrage(o);
            indexationDocumentTitre(o);
            indexationDocumentContenu(o);
        } else {
            EntreSortie.afficherMessage("Ouvrage existant\n");
        }
        return o;
    }

    private void lierLecteur(Lecteur l, int num) {
        lecteurs.put(num, l);
    }

    private void lierElementRecherche(ElementRecherche e) {
        elements.add(e);
    }

    private void lierOuvrage(Ouvrage o) {
        ouvrages.put(o.getISBN(), o);
    }

    public void consulterLecteur() {
        int numLecteur;
        Lecteur l;
        numLecteur = EntreSortie.lireEntier("Veuillez donner le Numero lecteur?");
        l = unLecteur(numLecteur);
        if (l == null) {
            EntreSortie.afficherMessage("Lecteur inexsitant");
        } else {
            EntreSortie.afficherMessage(l.infoLecteur());
        }
    }

    public void consulterOuvrage() {
        String ISBN;
        Ouvrage o;
        ISBN = EntreSortie.lireChaine("Veuillez donner l'ISBN du livre?");
        o = unOuvrage(ISBN);
        if (o == null) {
            EntreSortie.afficherMessage("Ouvrage inexsitant");
        } else {
            EntreSortie.afficherMessage(o.infoOuvrage());
        }
    }

    public void consulterExemplairesOuvrage() {
        String ISBN;
        Ouvrage o;
        ISBN = EntreSortie.lireChaine("ISBN du livre?");
        o = unOuvrage(ISBN);
        if (o == null) {
            EntreSortie.afficherMessage("Ouvrage inexsitant");
        } else {
            EntreSortie.afficherMessage(o.infoOuvrage() + "\n" + o.infoExemplaire());
        }
    }

    private void lierElementRechercheDocumentContenue(DocumentContenu dc) {
        String nom, prenom;
        char continu;
        Auteur a;
        do {
            nom = EntreSortie.lireChaine("Nom de l'auteur : ");
            prenom = EntreSortie.lireChaine("Prenom de l'auteur : ");
            a = unAuteur(nom, prenom);
            if (a == null) {
                a = new Auteur(nom, prenom);
                lierElementRecherche(a);
            }
            a.lierDocumentElement(dc);
            dc.lierElementRecherche(a);
            continu = EntreSortie.lireChaine("Ajouter un autre auteur(o pour continuer)").charAt(0);
        } while (continu == 'o' || continu == 'O');
    }

    public void emprunterExemplaire() {
        Ouvrage o;
        Exemplaire e;
        String ISBN;
        int numExplaire, numLecteur = EntreSortie.lireEntier("Numéro lecteur:");
        Lecteur lecteur = unLecteur(numLecteur);
        if (lecteur != null) {
            if (lecteur.etatNonSature()) {
                ISBN = EntreSortie.lireChaine("ISBN du livre?");
                o = unOuvrage(ISBN);
                if (o != null) {
                    if (o.compatibiliteAge(lecteur.getAge())) {

                        numExplaire = EntreSortie.lireEntier("Numéro séquentiel de l'exemplaire:");
                        e = o.unExemplaire(numExplaire);
                        if (e != null) {
                            if (e.etatEprumtable()) {
                                lecteur.emprunter(e);
                                EntreSortie.afficherMessage("Emprunt realisé");
                            } else {
                                EntreSortie.afficherMessage("Exemplaire non empruntable");
                            }
                        } else {
                            EntreSortie.afficherMessage("Exemplaire inexistant\n");
                        }
                    } else {
                        EntreSortie.afficherMessage("Age non compatible");
                    }
                } else {
                    EntreSortie.afficherMessage("Ouvrage inexistant");
                }
            } else {
                EntreSortie.afficherMessage("Lecteur sature");
            }
        } else {
            EntreSortie.afficherMessage("Lecteur inexsitant");
        }
    }

    public void rendreExemplaire() {
        String ISBN = EntreSortie.lireChaine("Numéro ISBN du livre à rendre:");
        Ouvrage o = unOuvrage(ISBN);
        if (o != null) {
            int numSeq = EntreSortie.lireEntier("Numéro sequentiel de l'exemplaire:");
            Exemplaire e = o.unExemplaire(numSeq);
            if (e != null) {
                e.rendreExemplaire();
            } else {
                EntreSortie.afficherMessage("Exemplaire inexistant");
            }
        } else {
            EntreSortie.afficherMessage("Ouvrage inexistant");
        }
    }

    public void consulterEmpruntLecteur() {
        int numLec = EntreSortie.lireEntier("Numéro de lecteur:");
        Lecteur l = unLecteur(numLec);
        if (l != null) {
            String info = l.infoLecteurSimple();
            info += "\nEmprunt(s):\n" + l.infoEmprunt();
            EntreSortie.afficherMessage(info);
        } else {
            EntreSortie.afficherMessage("Lecteur inexistant");
        }
    }

    public void relancerLecteur() {
        String str = "";
        for (int num : lecteurs.keySet()) {
            Lecteur lecteur = lecteurs.get(num);
            str += lecteur.mesEmpruntsRetard() + "\n";
        }
        EntreSortie.afficherMessage(str);
    }

    public void enregistrePeriodique() {
        String ISSN;
        ISSN = EntreSortie.lireChaine("ISSN du périodique : ");
        Periodique p = unPeriodique(ISSN);
        if (p == null) {
            String titre, editeur;
            char periodicite;
            Periodicite per;
            titre = EntreSortie.lireChaine("Titre du périodique : ");
            periodicite = EntreSortie.lireChaine("Periodicité du périodique(Quotidienne, Hebdomadaire, Mensuelle, Bimensuelle, Trimestrielle, Semestrielle, Annuelle) : ").charAt(0);
            editeur = EntreSortie.lireChaine("Editeur du périodique : ");
            switch (periodicite) {
                default:
                case 'Q':
                case 'q':
                    per = Periodicite.quotidienne;
                    break;
                case 'H':
                case 'h':
                    per = Periodicite.hebdomadaire;
                    break;
                case 'M':
                case 'm':
                    per = Periodicite.mensuelle;
                    break;
                case 'B':
                case 'b':
                    per = Periodicite.bimensuelle;
                    break;
                case 'T':
                case 't':
                    per = Periodicite.trimestrielle;
                    break;
                case 'S':
                case 's':
                    per = Periodicite.semestrielle;
                    break;
            }
            p = new Periodique(ISSN, titre, editeur, per);
            lierPeriodique(p, ISSN);
            indexationDocumentTitre(p);
            EntreSortie.afficherMessage("Périodique enregistré");
        } else {
            EntreSortie.afficherMessage("Périodique existant");

        }
    }

    private Periodique unPeriodique(String ISSN) {
        return periodiques.get(ISSN);
    }

    private void lierPeriodique(Periodique p, String ISSN) {
        periodiques.put(ISSN, p);
    }

    public void enrgistrerParution() {
        String ISSN = EntreSortie.lireChaine("ISSN du périodique?");
        Periodique per = unPeriodique(ISSN);
        if (per != null) {
            String numeroParution = EntreSortie.lireChaine("Numéro de la parution?");
            Parution par = per.getParutionPeriodique(numeroParution);
            if (par == null) {
                String titre = EntreSortie.lireChaine("Titre de la parution : ");
                GregorianCalendar date = EntreSortie.lireDate("Date de la parution : ");
                par = per.creerParution(numeroParution, titre, date);
                char continu;
                do {
                    titre = EntreSortie.lireChaine("Titre de l'article : ");
                    int numeroPage = EntreSortie.lireEntier("Numero de page de l'article : ");
                    Article art = par.creerArticle(titre, numeroPage);
                    do {
                        String nom = EntreSortie.lireChaine("Nom de l'auteur : ");
                        String prenom = EntreSortie.lireChaine("Prenom de l'auteur : ");
                        Auteur a = unAuteur(nom, prenom);
                        if (a == null) {
                            a = new Auteur(nom, prenom);
                            lierElementRecherche(a);
                        }
                        art.lierElementRecherche(a);
                        a.lierDocumentElement(art);
                        continu = EntreSortie.lireChaine("O pour ajouter plus d'auteurs").charAt(0);
                    } while (continu == 'o' || continu == 'O');
                    indexationDocumentTitre(art);
                    indexationDocumentContenu(art);
                    continu = EntreSortie.lireChaine("O pour ajouter plus d'articles").charAt(0);
                } while (continu == 'o' || continu == 'O');
            } else {
                EntreSortie.afficherMessage("Parution existante");
            }
        } else {
            EntreSortie.afficherMessage("Périodique inexistant");
        }
    }

    public void consulterParution() {
        String resultat = "";
        String ISSN = EntreSortie.lireChaine("ISSN du périodique : ");
        Periodique per = unPeriodique(ISSN);
        if (per != null) {
            String numeroParution = EntreSortie.lireChaine("Numero de la parution : ");
            Parution par = per.getParution(numeroParution);
            if (par != null) {
                resultat += per.infoDocument();
                resultat += par.infoParution();
                resultat += par.infoParutionArticle();
                EntreSortie.afficherMessage(resultat);
            } else {
                EntreSortie.afficherMessage("Parution inexistant");
            }
        } else {
            EntreSortie.afficherMessage("Périodique inexistant");
        }
    }

    public void consulterPeriodique() {
        String resultat = "";
        String ISSN = EntreSortie.lireChaine("ISSN du périodique : ");
        Periodique per = unPeriodique(ISSN);
        if (per != null) {
            resultat += per.infoDocument();
            EntreSortie.afficherMessage(resultat);
        } else {
            EntreSortie.afficherMessage("Périodique inexistant");
        }
    }

    public void rechercheNomAuteur() {
        String nom = EntreSortie.lireChaine("Nom de l'auteur : ");
        String prenom = EntreSortie.lireChaine("Prenom de l'auteur : ");

        Auteur a = unAuteur(nom, prenom);

        if (a == null) {
            EntreSortie.afficherMessage("Auteur inexistant");
        } else {
            String info = a.rechercheInfoDocument();
            EntreSortie.afficherMessage(info);
        }
    }

    public void rechercheMotClefTitre() {
        String mot = EntreSortie.lireChaine("Mot clef titre: ");
        MotClefTitre m = unMotClefTitre(mot);
        if (m != null) {
            EntreSortie.afficherMessage(m.rechercheInfoDocument() + "\n");
        } else {
            EntreSortie.afficherMessage("Aucun document trouvé avec ce mot clef");
        }
    }

    public void rechercheMotClefContenu() {
        String mot = EntreSortie.lireChaine("Mot clef contenu: ");
        MotClefContenu m = unMotClefContenu(mot);
        if (m != null) {
            EntreSortie.afficherMessage(m.rechercheInfoDocument());
        } else {
            EntreSortie.afficherMessage("Aucun document trouvé avec ce mot clef");
        }
    }

    private void indexationDocumentContenu(DocumentContenu dc) {
        String mot = EntreSortie.lireChaine("Mots Clefs :");
        HashSet<String> mots = new HashSet<String>();
        StringTokenizer motsTemp = new StringTokenizer(mot, " ");
        while (motsTemp.hasMoreTokens()) {
            mots.add(motsTemp.nextToken());
        }
        for (String str : mots) {
            MotClefContenu m = unMotClefContenu(str);
            if (m == null) {
                m = new MotClefContenu(str);
                lierElementRecherche(m);
            }
            dc.lierElementRecherche(m);
            m.lierDocumentElement(dc);
        }
    }

    private void indexationDocumentTitre(Document d) {
        HashSet<String> mots = new HashSet<String>();

        String nomfich = "Mots.txt";
        MotClefTitre m;
        StringTokenizer motsTemp = new StringTokenizer(d.getTitre(), " ");
        while (motsTemp.hasMoreTokens()) {
            mots.add(motsTemp.nextToken());
        }
        for (String str : mots) {
            if (!MotClefTitre.mots.contains(str)) {
                m = unMotClefTitre(str);
                if (m == null) {
                    m = new MotClefTitre(str);
                    lierElementRecherche(m);
                }
                d.lierElementRecherche(m);
                m.lierDocumentElement(d);
            }
        }
    }
}
